package com.api.league.service.impl;

import com.api.core.service.AbstractService;
import com.api.league.dao.*;
import com.api.league.enums.FixtureStatus;
import com.api.league.enums.LeagueStatus;
import com.api.league.form.CreateLeagueForm;
import com.api.league.model.League;
import com.api.league.model.LeagueIntroduction;
import com.api.league.model.LeagueTopPlayer;
import com.api.league.service.LeagueService;
import com.api.league.vo.LeagueFixtureVo;
import com.api.league.vo.LeagueTopPlayerVo;
import com.api.league.vo.LeagueVo;
import com.api.user.service.GameService;
import com.api.user.vo.GameVo;
import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author RenQiang
 * @date 2021/5/26
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class LeagueServiceImpl extends AbstractService<League> implements LeagueService {
    private final LeagueIntroductionMapper leagueIntroductionMapper;
    private final LeagueMapper leagueMapper;
    private final GameService gameService;
    private final LeagueMatchDayMapper leagueMatchDayMapper;
    private final LeagueFixtureMapper leagueFixtureMapper;
    private final LeagueHighlightMapper leagueHighlightMapper;
    private final LeagueTeamMapper leagueTeamMapper;
    private final LeagueTransferMapper leagueTransferMapper;
    private final LeagueStandingMapper leagueStandingMapper;
    private final LeagueTopPlayerMapper leagueTopPlayerMapper;

    public LeagueServiceImpl(LeagueIntroductionMapper leagueIntroductionMapper, LeagueMapper leagueMapper, GameService gameService, LeagueMatchDayMapper leagueMatchDayMapper, LeagueFixtureMapper leagueFixtureMapper, LeagueHighlightMapper leagueHighlightMapper, LeagueTeamMapper leagueTeamMapper, LeagueTransferMapper leagueTransferMapper, LeagueStandingMapper leagueStandingMapper, LeagueTopPlayerMapper leagueTopPlayerMapper) {
        this.leagueIntroductionMapper = leagueIntroductionMapper;
        this.leagueMapper = leagueMapper;
        this.gameService = gameService;
        this.leagueMatchDayMapper = leagueMatchDayMapper;
        this.leagueFixtureMapper = leagueFixtureMapper;
        this.leagueHighlightMapper = leagueHighlightMapper;
        this.leagueTeamMapper = leagueTeamMapper;
        this.leagueTransferMapper = leagueTransferMapper;
        this.leagueStandingMapper = leagueStandingMapper;
        this.leagueTopPlayerMapper = leagueTopPlayerMapper;
    }

    @Override
    public void createLeague(CreateLeagueForm form) {
        League league = new League();
        league.setPoster(form.getPoster());
        league.setGameId(form.getGameId());
        league.setTitle(form.getTitle());
        league.setCreateTime(new Date());
        league.setLeagueType(form.getLeagueType());
        league.setMatchDayCount(0);
        super.save(league);
        if (StringUtils.isNotEmpty(form.getIntroduction())) {
            LeagueIntroduction leagueIntroduction = new LeagueIntroduction();
            leagueIntroduction.setLeagueId(league.getId());
            leagueIntroduction.setIntroduction(form.getIntroduction());
            leagueIntroductionMapper.insertSelective(leagueIntroduction);
        }
    }

    @Override
    public List<LeagueVo> findByGameCategoryId(Long gameCategoryId, LeagueStatus leagueStatus) {
        Map<String, Object> paramMap = new HashMap<>(4);
        paramMap.put("gameCategoryId", gameCategoryId);
        paramMap.put("leagueStatus", leagueStatus);
        List<League> leagues = leagueMapper.selectListByParams(paramMap);
        List<Long> gameIds = leagues.stream()
                .map(League::getGameId)
                .distinct()
                .collect(Collectors.toList());
        Map<Long, GameVo> gameIdVoMap = gameService.getIdVoMap(gameIds);
        return leagues.stream()
                .map(league -> {
                    LeagueVo leagueVo = new LeagueVo();
                    BeanUtils.copyProperties(league, leagueVo);
                    leagueVo.setGame(gameIdVoMap.get(league.getGameId()));
                    return leagueVo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public void deleteLeague(Long leagueId) {
        leagueMapper.deleteByPrimaryKey(leagueId);
        leagueIntroductionMapper.deleteByLeagueId(leagueId);
        leagueFixtureMapper.deleteByLeagueId(leagueId);
        leagueStandingMapper.deleteByLeagueId(leagueId);
        leagueMatchDayMapper.deleteByLeagueId(leagueId);
        leagueHighlightMapper.deleteByLeagueId(leagueId);
        leagueTeamMapper.deleteByLeagueId(leagueId);
        leagueTransferMapper.deleteByLeagueId(leagueId);
    }

    @Override
    public List<LeagueTopPlayerVo> getTopPlayers(Long leagueId) {
        return leagueTopPlayerMapper.getByLeagueId(leagueId);
    }

    @Override
    public void updateTopPlayer(Long leagueId, Integer rank, Long teamId, Long playerId) {
        LeagueTopPlayer leagueTopPlayer = new LeagueTopPlayer();
        leagueTopPlayer.setLeagueId(leagueId);
        leagueTopPlayer.setRank(rank);
        leagueTopPlayer.setTeamId(teamId);
        leagueTopPlayer.setPlayerId(playerId);
        leagueTopPlayer.setCreateTime(new Date());
        leagueTopPlayer.setUpdateTime(new Date());
        leagueTopPlayerMapper.insertOrUpdate(leagueTopPlayer);
    }

    @Override
    public void archiveById(Long leagueId) {
        League league = leagueMapper.selectByPrimaryKey(leagueId);
        Preconditions.checkArgument(league != null, "League doesn't exist!");
        List<LeagueFixtureVo> allFixtures = leagueFixtureMapper.findFixtureByPage(leagueId);
        Preconditions.checkArgument(allFixtures.stream()
                .allMatch(fixture -> fixture.getStatus() == FixtureStatus.Finished), "Some fixtures doesn't finish, you can't archive this league!");

        league.setStatus(LeagueStatus.Finished);
        league.setUpdateTime(new Date());
        leagueMapper.updateByPrimaryKey(league);
    }
}
